/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OHOS_AVPLAYBACK_STATE_H
#define OHOS_AVPLAYBACK_STATE_H

/**
 * @addtogroup avsession
 * @{
 *
 * @brief Provides APIs for audio and video (AV) media control.
 *
 * The APIs can be used to create, manage, and control media sessions.
 *
 * @syscap SystemCapability.Multimedia.AVSession.Core
 * @since 9
 * @version 1.0
 */

/**
 * @file avplayback_state.h
 *
 * @brief Declares the AV playback states.
 *
 * @since 9
 * @version 1.0
 */

#include <bitset>
#include <parcel.h>

namespace OHOS::AVSession {
/**
 * @brief Represents a playback state class that provides APIs for obtaining and setting the playback UI information.
 */
class AVPlaybackState : public Parcelable {
public:

    /**
     * @brief Enumerates the playback states.
     *
     */
    enum {
        /** Initial. */
        PLAYBACK_STATE_INITIAL = 0,
        /** Preparing. */
        PLAYBACK_STATE_PREPARING = 1,
        /** Playing. */
        PLAYBACK_STATE_PLAYING = 2,
        /** Paused. */
        PLAYBACK_STATE_PAUSED = 3,
        /** Fast forwarding. */
        PLAYBACK_STATE_FAST_FORWARD = 4,
        /** Rewinding. */
        PLAYBACK_STATE_REWIND = 5,
        /** Stopped. */
        PLAYBACK_STATE_STOP = 6,
        /** Invalid value, which is used internally to determine whether a state is valid. */
        PLAYBACK_STATE_MAX = 7
    };

    /**
     * @brief Enumerates the information on the playback UI.
     *
     */
    enum {
        /** Playback state. */
        PLAYBACK_KEY_STATE = 0,
        /** Playback speed. */
        PLAYBACK_KEY_SPEED = 1,
        /** Playback position. */
        PLAYBACK_KEY_POSITION = 2,
        /** Buffered time. */
        PLAYBACK_KEY_BUFFERED_TIME = 3,
        /** Loop mode. */
        PLAYBACK_KEY_LOOP_MODE = 4,
        /** Favorite button. */
        PLAYBACK_KEY_IS_FAVORITE = 5,
        /** Invalid value, which is used internally to determine whether a key is valid. */
        PLAYBACK_KEY_MAX = 6
    };

    /**
     * @brief Enumerates the loop modes.
     *
     */
    enum {
        /** Sequential playback. */
        LOOP_MODE_SEQUENCE = 0,
        /** Single loop. */
        LOOP_MODE_SINGLE = 1,
        /** Playlist loop. */
        LOOP_MODE_LIST = 2,
        /** Shuffle. */
        LOOP_MODE_SHUFFLE = 3
    };

    /**
     * @brief Describes the playback position.
     *
     * @since 9
     * @version 1.0
     */
    struct Position {
        /** Time that the playback has been reached, in ms. */
        int64_t elapsedTime_ {};
        /** Update timestamp, in ms. */
        int64_t updateTime_ {};
    };

    using PlaybackStateMaskType = std::bitset<PLAYBACK_KEY_MAX>;

    AVPlaybackState();
    ~AVPlaybackState() override = default;

    /**
     * @brief Unmarshals IPC data from a {@link Parcel} object.
     *
     * This API unmarshals the information of the {@link Parcel} type received through the IPC to
     * information of the {@link AVPlaybackState} type.
     *
     * @param parcel Indicates the pointer to the {@link Parcel} object for unmarshalling.
     * @return Returns the pointer to an {@link AVPlaybackState} object if the operation is successful;
     * returns a null pointer otherwise.
     * @see Marshalling
     * @since 9
     * @version 1.0
     */
    static AVPlaybackState* Unmarshalling(Parcel& parcel);

    /**
     * @brief Marshals IPC data into a {@link Parcel} object.
     *
     * This API marshals information of the {@link AVPlaybackState} type 
     * into information of the {@link Parcel} type for IPC.
     *
     * @param parcel Indicates the pointer to the {@link Parcel} object for marshalling.
     * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
     * @see Unmarshalling
     * @since 9
     * @version 1.0
     */
    bool Marshalling(Parcel& parcel) const override;

    /**
     * @brief Checks the validity of the current information.
     *
     * @return Returns <b>true</b> if the information is valid; returns <b>false</b> otherwise.
     * @since 9
     * @version 1.0
     */
    bool IsValid() const;

    /**
     * @brief Sets a playback state.
     *
     * @param state Indicates the playback state to set, which must be within the range
     * from {@link #PLAYBACK_STATE_INITIAL} to {@link #PLAYBACK_STATE_MAX}.
     * @see GetState
     * @since 9
     * @version 1.0
     */
    void SetState(int32_t state);

    /**
     * @brief Obtains the playback state.
     *
     * @return Returns the playback state, which is within the range
     * from {@link #PLAYBACK_STATE_INITIAL} to {@link #PLAYBACK_STATE_MAX}.
     * @see SetState
     * @since 9
     * @version 1.0
     */
    int32_t GetState() const;

    /**
     * @brief Sets a playback speed.
     *
     * @param speed Indicates the playback speed to set.
     * @see SetSpeed
     * @since 9
     * @version 1.0
     */
    void SetSpeed(double speed);

    /**
     * @brief Obtains the playback speed.
     *
     * @return Returns the current playback speed.
     * @see SetSpeed
     * @since 9
     * @version 1.0
     */
    double GetSpeed() const;

    /**
     * @brief Sets the playback position, which is calculated based on the update time and elapsed time, in ms.
     *
     * @param position Indicates the pointer to the playback position to set, which is a {@link Position} object.
     * @see GetPosition
     * @since 9
     * @version 1.0
     */
    void SetPosition(const Position& position);

    /**
     * @brief Obtains the playback position.
     *
     * @return Returns the playback position, which is a {@link Position} object.
     * @see SetPosition
     * @since 9
     * @version 1.0
     */
    Position GetPosition() const;

    /**
     * @brief Sets the buffered time.
     *
     * @param time Indicates the buffered time to set, in ms.
     * @see GetBufferedTime
     * @since 9
     * @version 1.0
     */
    void SetBufferedTime(int64_t time);

    /**
     * @brief Obtains the buffered time.
     *
     * @return Returns the buffered time, in ms.
     * @see SetBufferedTime
     * @since 9
     * @version 1.0
     */
    int64_t GetBufferedTime() const;

    /**
     * @brief Sets a loop mode.
     *
     * @param mode Indicates the loop mode to set, which must be within the range
     * from {@link #LOOP_MODE_SEQUENCE} to {@link #LOOP_MODE_SHUFFLE}.
     * @see GetLoopMode
     * @since 9
     * @version 1.0
     */
    void SetLoopMode(int32_t mode);

    /**
     * @brief Obtains the loop mode.
     *
     * @param Returns the loop mode, which is within the range 
     * from {@link #LOOP_MODE_SEQUENCE} to {@link #LOOP_MODE_SHUFFLE}.
     * @see SetLoopMode
     * @since 9
     * @version 1.0
     */
    int32_t GetLoopMode() const;

    /**
     * @brief Sets whether to favorite the track.
     *
     * @param isFavorite Specifies whether to favorite the track. 
     * The value <b>true</b> means to favorite the track, and <b>false</b> means the opposite.
     * @see GetFavorite
     * @since 9
     * @version 1.0
     */
    void SetFavorite(bool isFavorite);

    /**
     * @brief Checks whether this track is favorited.
     *
     * @return Returns <b>true</b> if the track is favorited; returns <b>false</b> otherwise.
     * @see SetFavorite
     * @since 9
     * @version 1.0
     */
    bool GetFavorite() const;

    /**
     * @brief Obtains the mask of the playback UI information.
     *
     * @return Returns the mask, which is a {@link PlaybackStateMaskType} object.
     * @see CopyFrom
     * @since 9
     * @version 1.0
     */
    PlaybackStateMaskType GetMask() const;

    /**
     * @brief Clones the playback UI information to a new {@link AVPlaybackState} object by mask.
     *
     * The object that corresponds to the mask and has a value will be cloned to {@code out}.
     *
     * @param mask Indicates the pointer to the mask of the playback UI information, 
     * which is a {@link PlaybackStateMaskType} object.
     * @param out Indicates the pointer to the {@link AVPlaybackState} object.
     * @return Returns <b>true</b> if one or more pieces of playback UI information are cloned;
     * returns <b>false</b> otherwise.
     * @see CopyFrom
     * @since 9
     * @version 1.0
     */
    bool CopyToByMask(PlaybackStateMaskType& mask, AVPlaybackState& out) const;

    /**
     * @brief Clones the information of the {@link AVPlaybackState} type to this object based on the mask of this object.
     *
     * @param in Indicates the pointer to the {@link AVPlaybackState} object.
     * @return Returns <b>true</b> if one or more pieces of playback UI information are cloned;
     * returns <b>false</b> otherwise.
     * @see CopyToByMask
     * @see GetMask
     * @since 9
     * @version 1.0
     */
    bool CopyFrom(const AVPlaybackState& in);
    
    /**
     * @brief Defines an inline function pointer array, which is used for distributed services
     * to set the playback UI information.
     *
     * @since 9
     * @version 1.0
     */
    const static inline std::vector<int32_t> localCapability {
        PLAYBACK_KEY_STATE,
        PLAYBACK_KEY_SPEED,
        PLAYBACK_KEY_POSITION,
        PLAYBACK_KEY_BUFFERED_TIME,
        PLAYBACK_KEY_LOOP_MODE,
        PLAYBACK_KEY_IS_FAVORITE,
    };

private:

    /**
     * @brief Mask of the playback UI information.
     *
     * If the mask is <b>1</b>, this object contains the UI information in a {@link PlaybackStateMaskType} object.
     */
    PlaybackStateMaskType mask_;

    /**
     * @brief AV playback state {@link #PLAYBACK_STATE_INITIAL}.
     *
     */
    int32_t state_ = PLAYBACK_STATE_INITIAL;

    /**
     * @brief Playback speed.
     *
     */
    double speed_ = 1.0;

    /**
     * @brief Playback position, which is a {@link Position} object.
     *
     */
    Position position_;

    /**
     * @brief Buffered time.
     *
     */
    int64_t bufferedTime_ {};

    /**
     * @brief Loop mode {@link #LOOP_MODE_SEQUENCE}.
     *
     */
    int32_t loopMode_ = LOOP_MODE_SEQUENCE;

    /**
     * @brief Favorite setting.
     *
     */
    bool isFavorite_ {};

    /**
     * @brief Clones the playback state.
     *
     * @param from Indicates the pointer to the source, which is an {@link AVPlaybackState} object.
     * @param to Indicates the pointer to the target, which is an {@link AVPlaybackState} object.
     * @since 9
     * @version 1.0
     */
    static void CloneState(const AVPlaybackState& from, AVPlaybackState& to);

    /**
     * @brief Clones the playback speed.
     *
     * @param from Indicates the pointer to the source, which is an {@link AVPlaybackState} object.
     * @param to Indicates the pointer to the target, which is an {@link AVPlaybackState} object.
     * @since 9
     * @version 1.0
     */
    static void CloneSpeed(const AVPlaybackState& from, AVPlaybackState& to);

    /**
     * @brief Clones the playback position.
     *
     * @param from Indicates the pointer to the source, which is an {@link AVPlaybackState} object.
     * @param to Indicates the pointer to the target, which is an {@link AVPlaybackState} object.
     * @since 9
     * @version 1.0
     */
    static void ClonePosition(const AVPlaybackState& from, AVPlaybackState& to);

    /**
     * @brief Clones the buffered time.
     *
     * @param from Indicates the pointer to the source, which is an {@link AVPlaybackState} object.
     * @param to Indicates the pointer to the target, which is an {@link AVPlaybackState} object.
     * @since 9
     * @version 1.0
     */
    static void CloneBufferedTime(const AVPlaybackState& from, AVPlaybackState& to);

    /**
     * @brief Clones the loop mode.
     *
     * @param from Indicates the pointer to the source, which is an {@link AVPlaybackState} object.
     * @param to Indicates the pointer to the target, which is an {@link AVPlaybackState} object.
     * @since 9
     * @version 1.0
     */
    static void CloneLoopMode(const AVPlaybackState& from, AVPlaybackState& to);

    /**
     * @brief Clones the favorite setting.
     *
     * @param from Indicates the pointer to the source, which is an {@link AVPlaybackState} object.
     * @param to Indicates the pointer to the target, which is an {@link AVPlaybackState} object.
     * @since 9
     * @version 1.0
     */
    static void CloneIsFavorite(const AVPlaybackState& from, AVPlaybackState& to);

    /**
     * @brief Defines the clone function pointer.
     *
     * @param from Indicates the pointer to the source, which is an {@link AVPlaybackState} object.
     * @param to Indicates the pointer to the target, which is an {@link AVPlaybackState} object.
     * @since 9
     * @version 1.0
     */
    using CloneActionType = void(*)(const AVPlaybackState& from, AVPlaybackState& to);

    /**
     * @brief Defines an inline function pointer array {@link AVPlaybackState} and {@link CloneActionType}.
     *
     * You can call a clone function by accessing <b>cloneActions[i]</b>.
     *
     */
    static inline CloneActionType cloneActions[PLAYBACK_KEY_MAX] = {
        [PLAYBACK_KEY_STATE] = &AVPlaybackState::CloneState,
        [PLAYBACK_KEY_SPEED] = &AVPlaybackState::CloneSpeed,
        [PLAYBACK_KEY_POSITION] = &AVPlaybackState::ClonePosition,
        [PLAYBACK_KEY_BUFFERED_TIME] = &AVPlaybackState::CloneBufferedTime,
        [PLAYBACK_KEY_LOOP_MODE] = &AVPlaybackState::CloneLoopMode,
        [PLAYBACK_KEY_IS_FAVORITE] = &AVPlaybackState::CloneIsFavorite,
    };
};
} // namespace OHOS::AVSession
/** @} */
#endif // OHOS_AVPLAYBACK_STATE_H
